home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume91 / aplictns / quiz_1_0 / part02 < prev   
Encoding:
Internet Message Format  |  1991-04-10  |  59.2 KB

  1. Path: news.larc.nasa.gov!amiga-request
  2. From: amiga-request@ab20.larc.nasa.gov (Amiga Sources/Binaries Moderator)
  3. Subject: v91i085: Quiz 1.0 - question and answer program, Part02/02
  4. Reply-To: creubank@is.crl.sony.co.jp
  5. Newsgroups: comp.sources.amiga
  6. Message-ID: <comp.sources.amiga:v91i085@ab20.larc.nasa.gov>
  7. References: <comp.sources.amiga:v91i084@ab20.larc.nasa.gov>
  8. Date: 10 Apr 91 14:57:39 GMT
  9. Approved: tadguy@uunet.UU.NET (Tad Guy)
  10. X-Mail-Submissions-To: amiga@uunet.uu.net
  11. X-Post-Discussions-To: comp.sys.amiga.misc
  12.  
  13. Submitted-by: creubank@is.crl.sony.co.jp
  14. Posting-number: Volume 91, Issue 085
  15. Archive-name: applications/quiz-1.0/part02
  16.  
  17. #!/bin/sh
  18. # This is a shell archive.  Remove anything before this line, then unpack
  19. # it by saving it into a file and typing "sh file".  To overwrite existing
  20. # files, type "sh file -c".  You can also feed this as standard input via
  21. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  22. # will see the following message at the end:
  23. #        "End of archive 2 (of 2)."
  24. # Contents:  parse.c quiz.c screen.c
  25. # Wrapped by tadguy@ab20 on Wed Apr 10 10:57:36 1991
  26. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  27. if test -f 'parse.c' -a "${1}" != "-c" ; then 
  28.   echo shar: Will not clobber existing file \"'parse.c'\"
  29. else
  30. echo shar: Extracting \"'parse.c'\" \(11191 characters\)
  31. sed "s/^X//" >'parse.c' <<'END_OF_FILE'
  32. X/***
  33. X ***  parse.c
  34. X ***
  35. X ***  Curtis Eubanks
  36. X ***  3 November 1989
  37. X ***
  38. X ***/
  39. X
  40. X#include <stdio.h>
  41. X#include <string.h>
  42. X
  43. X#include <exec/types.h> /* only for def'n of 'node' */
  44. X#include <exec/lists.h> /* needed in qstructs.h     */
  45. X
  46. X/*#ifndef EXEC_MEMORY_H
  47. X#include <exec/memory.h>
  48. X#endif
  49. X*/
  50. X#define GLOBALVAR extern
  51. X#include "qstructs.h"
  52. Xextern char *mymalloc();
  53. X
  54. Xvoid slistAdd();
  55. Xstruct slist *Makeslist();
  56. Xint slistSize();
  57. Xvoid remwh();
  58. Xchar *findfirstbrace();
  59. Xchar *findlevel();
  60. Xvoid deletebrackets();
  61. Xchar *snarfbrackets();
  62. Xvoid printslist();
  63. Xstruct slist *FindOrs();
  64. Xstruct slist *findors();
  65. Xint checkbrackets();
  66. Xstruct slist *joinslists();
  67. Xchar *findmatchbrace();
  68. Xstruct slist *expandslist();
  69. Xstruct slist *expand();
  70. X
  71. X/* Add a single string to slist sl.  Does not copy */
  72. Xvoid slistAdd(sl,s) struct slist *sl; char *s;
  73. X{
  74. X  while (sl->next) sl = sl->next;
  75. X  sl->next = (struct slist *)mymalloc(sizeof(struct slist));
  76. X  (sl->next)->s = s;
  77. X  (sl->next)->next = NULL;
  78. X} /* slistAdd */
  79. X
  80. X/* returns the number of elems in sl */
  81. Xint slistSize(sl) struct slist *sl;
  82. X{
  83. X int rtn=0;
  84. X while (sl) rtn++, sl=sl->next;
  85. X return(rtn);
  86. X} /* slistSize */
  87. X
  88. X/* allocate and return a new slist structure and fill it with 's' */
  89. Xstruct slist *Makeslist(s) char *s;
  90. X{
  91. X  struct slist *rtn;
  92. X  rtn = (struct slist *)mymalloc(sizeof(struct slist));
  93. X  rtn->s = s;
  94. X  rtn->next = NULL;
  95. X  return(rtn);
  96. X} /* Makeslist */
  97. X
  98. X/* whitespace macro */
  99. X#define iswhite(x) ((x == ' ')||(x == '\t'))
  100. X
  101. X/* modifies s by removing leading & trailing whitespace and replacing
  102. X   any other whitespace with a single space */
  103. Xvoid remwh(s) char *s;
  104. X{
  105. X  char *r;
  106. X  r = s; /* start scanning at the beginning */
  107. X  if (!(*s)) return; /* a null string could mess us up */
  108. X  while (1) {
  109. X    while ((*r) && iswhite(*r)) r++;
  110. X    if (!(*r)) {
  111. X      /* we may have to delete a single ' ' at the end */
  112. X      /* since we already check for a null string passed to remwh, */
  113. X      /* we know that *(s-1) is a valid address */
  114. X      if (iswhite(*(s-1))) *(s-1) = '\0';
  115. X      else *s = '\0';
  116. X      return;
  117. X    } /* if !*r */
  118. X    /* now copy till next white */
  119. X    while ((*r) && (!(iswhite(*r)))) *s++ = *r++;
  120. X    if (*r) *s++ = ' '; /* replace white with a space */
  121. X    } /* while (1) */
  122. X} /* remwh */
  123. X
  124. X/* returns the address of the first opening brace '{' in s.
  125. X   If none found, returns NULL */
  126. Xchar *findfirstbrace(s)
  127. X    char *s;
  128. X{
  129. X  while (*s) {
  130. X    if (*s == '{') return(s);
  131. X    s++;
  132. X   } /* while */
  133. X   return(NULL);
  134. X} /* findfirstbrace */
  135. X
  136. X/* returns the address of first opening brace in s that is nested level
  137. X   levels deep.  Returns NULL if not found */
  138. Xchar *findlevel(s, level)
  139. X    char *s;
  140. X    int level;
  141. X{
  142. X  int nest = 0;
  143. X
  144. X  if (level == 0) return(s);
  145. X  while (*s) {
  146. X    if (*s == '{') {
  147. X      nest++;
  148. X      if (nest==level) return(s+1);
  149. X    } /* if */
  150. X    else if (*s == '}') nest--;
  151. X    s++;
  152. X  } /* while */
  153. Xreturn(NULL);
  154. X} /* findlevel */
  155. X
  156. X/* Modifies s by deleting the first set of matching brackets in s.
  157. X   Requires s has at least one set of balanced brackets.
  158. X   deletebrackets("this {is {an} example} here") --> modifies s to -->
  159. X   "this is {an} example here" */
  160. Xvoid deletebrackets(s) char *s;
  161. X{
  162. X  int nest = 1;
  163. X  char *t;
  164. X
  165. X  while (*s != '{') s++;
  166. X  t = s+1;
  167. X  while (*t) {
  168. X    if (*t == '{') nest++;
  169. X    else if (*t == '}') {
  170. X      nest--;
  171. X      if (!nest) { t++; break; } /* found end brace */
  172. X      } /* else if */
  173. X  *s++ = *t++;
  174. X  } /* while *t */
  175. X  while (*t) *s++ = *t++; /* copy the rest of the string */
  176. X  *s = '\0';
  177. X} /* deletebrackets */
  178. X
  179. X/* snarfbrackets is the same as deletebrackets except that it actually
  180. X   deletes everything within and including the brackets.  Returns a NEW
  181. X   string.  Doesn't modify s.  Requires the brackets exist.
  182. X   snarfbrackets("this {is {an} example} here") = "this  here" */
  183. Xchar *snarfbrackets(s)
  184. X    char *s;
  185. X{
  186. X  char *first, *last, *rtn;
  187. X
  188. X  rtn = mymalloc(strlen(s)+1);
  189. X  (void)strcpy(rtn, s);
  190. X  first = findfirstbrace(rtn);
  191. X  if (!first)
  192. X    FatalError("Aiigghh!  Couldn't find first brace in %s\n",rtn);
  193. X  last = findmatchbrace(first)+1;
  194. X  if (!last)
  195. X    FatalError("Aiigghh!  Couldn't find matching brace in %s\n",first);
  196. X  while (*last) *first++ = *last++;
  197. X  *first = '\0';
  198. X  return(rtn);
  199. X}
  200. X
  201. X/* Prints out all the strings in an slist structure, each on a different
  202. X   line.  Used only for debugging */
  203. Xvoid printslist(sl) struct slist *sl;
  204. X{
  205. X  printf("Slist is:\n");
  206. X  while (sl) { printf("    \"%s\"\n",sl->s); sl = sl->next; }
  207. X  printf("\n");
  208. X}
  209. X
  210. X/* FindOrs returns a list of outermost level strings of s that are
  211. X   separated by '|'.  Requires s have balanced brackets.  If only one
  212. X   string is found, NULL is returned.
  213. X   FindOrs("one|{two|zwei|ni}|mikka") =
  214. X   { "one", "{two|zwei|ni}", "mikka"} */
  215. Xstruct slist *FindOrs(s) char *s;
  216. X{
  217. X  struct slist *rtn = NULL;
  218. X  int tmpsize, numfound = 0, nest = 0;
  219. X  char *lastword, *tmpstr;
  220. X
  221. X  if (*s == '\0') return(rtn);
  222. X  lastword = s;
  223. X  while (*s) {
  224. X    if (*s == '{') nest++;
  225. X    else if (*s == '}') nest--;
  226. X    if ((*s == '|')&&(!nest)) {
  227. X      numfound++;
  228. X      tmpsize = s-lastword+1;
  229. X      tmpstr = mymalloc(tmpsize);
  230. X      memcpy(tmpstr, lastword, tmpsize-1);
  231. X      tmpstr[tmpsize-1] = '\0';
  232. X      if (!rtn) rtn = Makeslist(tmpstr);
  233. X      else slistAdd(rtn, tmpstr);
  234. X      lastword = s+1;
  235. X      } /* if */
  236. X    s++;
  237. X    } /* while */
  238. X  if (numfound == 0) return(NULL);
  239. X  if (*lastword) {
  240. X    numfound++;
  241. X    tmpsize = s-lastword+1;
  242. X    tmpstr = mymalloc(tmpsize);
  243. X    memcpy(tmpstr, lastword, tmpsize-1);
  244. X    tmpstr[tmpsize-1] = '\0';
  245. X    if (!rtn) rtn = Makeslist(tmpstr);
  246. X    else slistAdd(rtn, tmpstr);
  247. X    } /* if */
  248. X   return(rtn);
  249. X} /* FindOrs */
  250. X
  251. X/* findors (probably not the best name) is similar to FindOrs, except
  252. X   that it returns the '|'-separated strings between the first set of
  253. X   balanced brackets.  Requires at least one set of balanced braces.
  254. X   findors("not in braces {a|b|{c|d}} not included") =
  255. X    { "a", "b", "{c|d}" } 
  256. X   As with FindOrs, findors returns NULL if only a single string is
  257. X   found or if s is an empty string or if no braces are found.  This
  258. X   was probably a bad idea. */
  259. Xstruct slist *findors(s) char *s;
  260. X{
  261. X  struct slist *rtn = NULL;
  262. X  int tmpsize, numfound = 0, nest = 1;
  263. X  char *lastword, *tmpstr;
  264. X
  265. X  if (*s == '\0') return(NULL);
  266. X
  267. X  lastword = findfirstbrace(s);
  268. X  if (!lastword) return(NULL); /* look ma, no braces */
  269. X  lastword++; /* point to actual string, not brace */
  270. X  s = lastword;
  271. X  while (*s) {
  272. X    if (*s=='{') nest++;
  273. X    else if (*s=='}') {
  274. X      nest--;
  275. X      if (!nest) {
  276. X        numfound++;
  277. X        tmpsize = s-lastword+1;
  278. X        tmpstr = mymalloc(tmpsize);
  279. X        memcpy(tmpstr, lastword, tmpsize-1);
  280. X        tmpstr[tmpsize-1] = '\0';
  281. X        if (!rtn) rtn = Makeslist(tmpstr);
  282. X        else slistAdd(rtn, tmpstr);
  283. X        break;
  284. X    } /* if !nest */
  285. X    } /* if close bracket */
  286. X    else if ((*s == '|') && (nest==1)) {
  287. X      numfound++;
  288. X      tmpsize = s-lastword+1;
  289. X      tmpstr = mymalloc(tmpsize);
  290. X      memcpy(tmpstr, lastword, tmpsize-1);
  291. X      tmpstr[tmpsize-1] = '\0';
  292. X      if (!rtn) rtn = Makeslist(tmpstr);
  293. X      else slistAdd(rtn, tmpstr);
  294. X      lastword = s+1;
  295. X      } /* if */
  296. X    s++;
  297. X    } /* while */
  298. X    if (numfound==1) return(NULL);
  299. X    return(rtn);
  300. X } /* findors */
  301. X
  302. X/* Returns deepest level of bracket nesting in a regular expression
  303. X   string.  Returns -1 if there is an error (unbalanced or unmatched
  304. X   brackets. */
  305. Xint checkbrackets(s) char *s;
  306. X{
  307. X  int nest = 0, maxlevel = 0;
  308. X
  309. X  while (*s) {
  310. X    if (*s == '{') {
  311. X      nest++;
  312. X      if (nest > maxlevel) maxlevel = nest;
  313. X      } /* if open brace */
  314. X    else if (*s == '}') {
  315. X      nest--;
  316. X      if (nest < 0) return(-1);
  317. X      } /* if close brace */
  318. X    s++;
  319. X    } /* while */
  320. X    if (nest != 0) return(-1);
  321. X    return(maxlevel);
  322. X} /* checkbrackets */
  323. X
  324. X/* Joins two slists by adding sl2 to the end of sl1.  Does not copy
  325. X   sl2.  Modifies sl1. There's really no reason to return sl1... */
  326. Xstruct slist *joinslists(sl1, sl2)
  327. X   struct slist *sl1, *sl2;
  328. X{
  329. X   struct slist *tmpslist; /* so we can return sl1 */
  330. X
  331. X   if (sl2) {
  332. X     tmpslist = sl1;
  333. X     while (tmpslist->next) tmpslist = tmpslist->next;
  334. X     tmpslist->next = sl2;
  335. X     } /* if sl2 */
  336. X   return(sl1);
  337. X} /* joinslists */
  338. X
  339. X/* find and return pointer to a matching brace; requires such a
  340. X   brace exists!  Returns NULL if not found. */
  341. Xchar *findmatchbrace(s)
  342. X    char *s;
  343. X{
  344. X  int nest = 0;
  345. X
  346. X  s = findfirstbrace(s);
  347. X  while (*s) {
  348. X    if (*s == '{') nest++;
  349. X    else if (*s == '}') {
  350. X      nest--;
  351. X      if (nest==0) return(s);
  352. X      } /* if close */
  353. X    s++;
  354. X    } /* while */
  355. X   return(NULL);
  356. X} /* findmatchbrace */
  357. X
  358. X/* expandslist expects a list of strings.  Each string is considered to
  359. X   be a simple regular expression of using '{', '}', and '|'.  The
  360. X   strings are expanded to all possibilities indicated by the regexp.
  361. X   "a|b|c" --> "a", "b", "c"
  362. X   "{x|y|z}-axis" --> "x-axis", "y-axis", "z-axis"
  363. X   "this {option} is fun" --> "this option is fun", "this  is fun" */
  364. Xstruct slist *expandslist(sl)
  365. X   struct slist *sl;
  366. X{
  367. X  struct slist *tmpslist, *rtn = NULL, workslist, *braceslist;
  368. X  char *bptr, *eptr, *newstr;
  369. X  int beforelength, afterlength;
  370. X
  371. X  workslist.next = NULL; /* used with a single string for efficiency */
  372. X  while (sl) { /* repeat for each string in sl */
  373. X    tmpslist = FindOrs(sl->s); /* get top level disjunctions */
  374. X    if (!tmpslist) {tmpslist=&workslist;workslist.s=sl->s;}
  375. X    while (tmpslist) {
  376. X      if (bptr = findfirstbrace(tmpslist->s)) { /* there is a brace */
  377. X        braceslist = findors(bptr); /* or tmpslist->s */
  378. X        if (!braceslist) { /* "{degenerate case}" */
  379. X          /* we want "{x}" to map to "x" and "" */
  380. X          slistAdd(sl, snarfbrackets(tmpslist->s)); /* "" */
  381. X          deletebrackets(tmpslist->s);
  382. X          slistAdd(sl, tmpslist->s);
  383. X          tmpslist = tmpslist->next;
  384. X          continue;
  385. X          } /* if "{x}" */
  386. X        eptr = findmatchbrace(bptr) + 1;
  387. X        beforelength = bptr - tmpslist->s;
  388. X        afterlength = tmpslist->s + strlen(tmpslist->s) - eptr;
  389. X        while (braceslist) {
  390. X          newstr = mymalloc(beforelength+strlen(braceslist->s)+afterlength+1);
  391. X          memcpy(newstr, tmpslist->s, beforelength);
  392. X          strcat(newstr, braceslist->s);
  393. X          strcat(newstr, eptr);
  394. X          slistAdd(sl, newstr);
  395. X          braceslist = braceslist->next;
  396. X          } /* while */
  397. X        } /* if there is a brace */
  398. X      else { /* no brace, just add the string to return list */
  399. X        if (!rtn) rtn = Makeslist(tmpslist->s);
  400. X        else slistAdd(rtn, tmpslist->s);
  401. X        } /* else */
  402. X      tmpslist = tmpslist->next; /* iterate */
  403. X      } /* while tmpslist */
  404. X    sl = sl->next; /* iterate */
  405. X    } /* while sl */
  406. X  return(rtn);
  407. X} /* expandslist */
  408. X
  409. X/* expand expands a single string by calling expandslist. */
  410. X/* returns the expanded slist, or NULL if error */
  411. Xstruct slist *expand(s) char *s;
  412. X{
  413. X  int level;
  414. X  struct slist *rtn, *tmpslist;
  415. X
  416. X  level = checkbrackets(s);
  417. X  if (level<0) {
  418. X    fprintf(stderr, "Unbalanced braces in \"%s\"\n", s);
  419. X    return(NULL);
  420. X    } /* if */
  421. X  rtn = expandslist(Makeslist(s));
  422. X  tmpslist = rtn;
  423. X  while (tmpslist) {
  424. X    remwh(tmpslist->s);
  425. X    tmpslist = tmpslist->next;
  426. X    } /* while */
  427. X  return(rtn);
  428. X} /* expand */
  429. END_OF_FILE
  430. if test 11191 -ne `wc -c <'parse.c'`; then
  431.     echo shar: \"'parse.c'\" unpacked with wrong size!
  432. fi
  433. # end of 'parse.c'
  434. fi
  435. if test -f 'quiz.c' -a "${1}" != "-c" ; then 
  436.   echo shar: Will not clobber existing file \"'quiz.c'\"
  437. else
  438. echo shar: Extracting \"'quiz.c'\" \(26723 characters\)
  439. sed "s/^X//" >'quiz.c' <<'END_OF_FILE'
  440. X/***
  441. X ***  quiz.c
  442. X ***  a question-answer game similar to /usr/games/quiz.
  443. X ***
  444. X ***  Curtis Eubanks
  445. X ***  19 October 1989  -- CLI only
  446. X ***  18 November 1989 -- graphics interface
  447. X ***
  448. X ***/
  449. X
  450. X/* screen.c funcs */
  451. Xextern void InitGraphics(), CloseGraphics(), redraw(),
  452. X  UpdateMenuGraphState();
  453. X
  454. X/* graph.c funcs */
  455. Xextern void cleargraph(),drawgraph(), UpdateCurrentQ();
  456. X
  457. X#include <exec/types.h>
  458. X#include <exec/lists.h>
  459. X#include <stdio.h>
  460. X#include <string.h>
  461. X#include <libraries/dos.h>
  462. X#include <libraries/dosextens.h>
  463. X#include <exec/memory.h>
  464. X#include <workbench/startup.h>
  465. X#include <stdlib.h> /* for srand & rand */
  466. X#include <intuition/intuition.h>
  467. X
  468. Xextern struct FileHandle *Open();
  469. Xextern long time();
  470. X/*#include <time.h>    for time()       */
  471. X
  472. X
  473. Xextern int bhandlemsg();
  474. Xextern ULONG ehandlemsg();
  475. Xextern struct NewWindow backnw;
  476. Xextern struct NewScreen ns;
  477. Xextern struct Window *backwindow;
  478. Xextern struct IntuiMessage *mes, *GetMsg();
  479. Xextern char *qtext, *atext, *sbuff, *ubuff, *ctext;
  480. Xextern struct StringInfo sStringInfo;
  481. Xextern void DrawQText();
  482. Xextern struct Gadget sgadget;
  483. X#define BEGINMENUNUM (SHIFTITEM(2)|SHIFTSUB(NOSUB))
  484. X
  485. X/* type definitions */
  486. X#define GLOBALVAR
  487. X#include "qstructs.h"
  488. X#include "parse.c.h"
  489. X#include "graph.h"
  490. X
  491. Xextern char *mymalloc(); /* in mymalloc.c */
  492. X
  493. X/* in graph.c */
  494. Xextern int readscore();
  495. Xextern int *AddTrial();
  496. Xextern void SetWorstQuestion();
  497. X
  498. X/***** function defs ******/
  499. Xvoid usage();
  500. Xvoid parseargs();
  501. Xstruct ResListItem *MakeNewItem();
  502. Xvoid FreeResource();
  503. Xvoid FreeAll();
  504. Xvoid CleanUp();
  505. Xchar *Allocate();
  506. Xvoid FatalError();
  507. Xvoid NonFatalError();
  508. Xint readfile();
  509. Xint countlines();
  510. Xint isin();
  511. Xchar *separate();
  512. Xvoid ask();
  513. Xvoid getinput();
  514. Xvoid correct();
  515. Xvoid wrong();
  516. Xchar **extractlines();
  517. Xvoid ilistAdd();
  518. Xilist *Makeilist();
  519. Xint ProcessQFile();
  520. Xvoid doswap();
  521. Xvoid stractivate();
  522. Xvoid MajorSwap();
  523. Xvoid quiz();
  524. Xvoid writescore();
  525. Xvoid main();
  526. X
  527. X
  528. X
  529. X
  530. Xvoid usage(s)
  531. X  char *s;
  532. X{
  533. X  printf("Usage: %s datafile [-switch] [-ignorecase] [-help]\n\n", s);
  534. X  printf("       -switch: questions and answers are switched\n");
  535. X  printf("       -ignorecase: case doesn't matter\n");
  536. X  printf("       -help: print this message (duh...)\n\n");
  537. X  printf("        You can use just the first letter of each option as\n");
  538. X  printf("        well.  datafile contains lines of the form\n");
  539. X  printf("        question:answer (one on each line)\n");
  540. X  exit(0);
  541. X}
  542. X
  543. X/* parses arguments and sets the appropriate qstate elements.       */
  544. X/* iff quiz was called with a filename, qstate.File is a non-empty  */
  545. X/* string.  */
  546. Xvoid parseargs(argc, argv)
  547. X  int argc;
  548. X  union {
  549. X           char **args;
  550. X           struct WBStartup *msg; 
  551. X         } *argv;
  552. X{
  553. X  if (argc==0) { /* Workbench startup */
  554. X    /*ns.DefaultTitle = argv->args[0];*/
  555. X    if (argv->msg->sm_NumArgs > 2)
  556. X      NonFatalError("%s: only one quiz file can be selected!\n");
  557. X    if (argv->msg->sm_NumArgs >= 2)
  558. X      strncpy(qstate.File, argv->msg->sm_ArgList[1].wa_Name,MAXFILENAME);
  559. X   }
  560. X  else { /* CLI startup */
  561. X   int i, gotfname=0;
  562. X   for (i=1; i<argc; i++) {
  563. X
  564. X    if ((!stricmp(argv->args[i], "-switch"))||
  565. X        (!stricmp(argv->args[i], "/switch"))||
  566. X        (!stricmp(argv->args[i], "-s")))
  567. X        qstate.Switch = 1;
  568. X
  569. X    else if ((!stricmp(argv->args[i], "-help"))||
  570. X        (!stricmp(argv->args[i], "/help"))||
  571. X        (!stricmp(argv->args[i], "-h")))
  572. X        usage(argv->args[0]); /* exits */
  573. X
  574. X    else if ((!stricmp(argv->args[i], "-ignorecase"))||
  575. X        (!stricmp(argv->args[i], "/ignorecase"))||
  576. X        (!stricmp(argv->args[i], "-i")))
  577. X        qstate.CaseSensitive = 0;
  578. X
  579. X    else if ((!stricmp(argv->args[i], "-dpen")) && (i+1 < argc))
  580. X        backnw.DetailPen = atoi(argv->args[++i]);
  581. X
  582. X    else if ((!stricmp(argv->args[i], "-bpen")) && (i+1 < argc))
  583. X        backnw.BlockPen = atoi(argv->args[++i]);
  584. X
  585. X    else if ((!stricmp(argv->args[i], "-sdpen")) && (i+1 < argc))
  586. X        ns.DetailPen = atoi(argv->args[++i]);
  587. X
  588. X    else if ((!stricmp(argv->args[i], "-sbpen")) && (i+1 < argc))
  589. X        ns.BlockPen = atoi(argv->args[++i]);
  590. X
  591. X    else if (gotfname)
  592. X        NonFatalError("Quiz: unrecognized option: %s.  Try -help\n",argv->args[i]);
  593. X    else {
  594. X        gotfname = 1;
  595. X        strncpy(qstate.File, argv->args[i], MAXFILENAME);
  596. X        } /* else */
  597. X    } /* for i */
  598. X  } /* CLI startup */
  599. X} /* parseargs */
  600. X
  601. Xstruct ResListItem *MakeNewItem(ptr, size, type)
  602. X   char *ptr;
  603. X   int size, type;
  604. X {
  605. X   struct ResListItem *rtn;
  606. X   extern char *AllocMem();
  607. X   rtn = (struct ResListItem *)AllocMem(sizeof(struct ResListItem), MEMF_CLEAR);
  608. X   if (rtn==NULL) {
  609. X      fprintf(stderr, "Ummm.  Big trouble: couldn't allocate NewItem\n");
  610. X      CleanUp(DONE_MSG);
  611. X      exit(-1); /* machine is really low on memory anyway */
  612. X      } /* if */
  613. X   rtn->ptr = ptr;
  614. X   rtn->size = size;
  615. X   rtn->type = type;
  616. X   return(rtn);
  617. X} /* MakeNewItem */
  618. X
  619. Xvoid FreeResource(Item)
  620. X  struct ResListItem *Item;
  621. X{
  622. Xswitch(Item->type) {
  623. X  case ALLOC_TYPE:
  624. X        if (Item->ptr) {
  625. X          FreeMem(Item->ptr, Item->size);  /* the real free */
  626. X          Item->ptr = NULL;
  627. X          } /* if */
  628. X    break;
  629. X  case LOCK_TYPE:
  630. X    UnLock((struct FileLock *)Item->ptr);
  631. X    break;
  632. X  case LIB_TYPE: /* these should be the last items released! */
  633. X        if (Item->ptr) CloseLibrary(Item->ptr); /* cast it to what? */
  634. X        break;
  635. X  case SCREEN_TYPE: /* should be 2nd to last item released! */
  636. X        if (Item->ptr) CloseScreen((struct Screen *)Item->ptr);
  637. X        break;
  638. X  case WINDOW_TYPE: /* must be closed AFTER screen! */
  639. X        if (Item->ptr) CloseWindow((struct Window *)Item->ptr);
  640. X        break;
  641. X  default:
  642. X    NonFatalError("FreeResource: unknown resource type: %ld\n",Item->type);
  643. X    break;
  644. X  } /* switch */
  645. X} /* FreeResource */
  646. X
  647. X/* FreeAll will free all memory that has been allocated via Allocate() */
  648. Xvoid FreeAll(ResListp)
  649. X     struct List *ResListp;
  650. X{
  651. X  extern void ForgetMemory(); /* mymalloc.c */
  652. X  struct ResListItem *node;
  653. X  struct List TmpList;
  654. X
  655. X  /* Here's the deal: we want to free all memory resources.  We will
  656. X     copy all non-memory resources into a temporary list, freeing up
  657. X     the memory resources as we go along. */
  658. X
  659. X  NewList(&TmpList);
  660. X
  661. X  while (node = (struct ResListItem *)RemTail(ResListp)) {
  662. X    if (node->type == ALLOC_TYPE) {
  663. X       FreeResource(node); FreeMem(node, sizeof(struct ResListItem));
  664. X       } /* if Alloc type */
  665. X    else
  666. X       AddTail(&TmpList, node);
  667. X    } /* while */
  668. X  /* this yields the original order */
  669. X  NewList(ResListp);
  670. X  while (node = (struct ResListItem *)RemTail(&TmpList))
  671. X     AddTail(ResListp, node);
  672. X
  673. X  ForgetMemory();  /* must do this!!!  This lets mymalloc know to start
  674. X                      allocating new memory and forget the old chunks  */
  675. X
  676. X} /* FreeAll */
  677. X
  678. X/* CleanUp keeps track of all resource allocations and will clean up
  679. X   when passed DONE_MSG.  Must be passed INIT_MSG initally */
  680. Xvoid CleanUp(msg, ptr, size)
  681. X  int msg;
  682. X  char *ptr;
  683. X  int size;
  684. X{
  685. X  struct ResListItem *NewItem;
  686. X  static struct List ResList;  /* this is the resource list */
  687. X  struct ResListItem *node;
  688. X
  689. Xswitch (msg) {
  690. X  case INIT_MSG:
  691. X    NewList(&ResList); /* initialize resource list */
  692. X    break;
  693. X  case ALLOC_MSG:
  694. X    /* first we have to allocate space for the NewItem.  If */
  695. X    /* this call fails, we're in big trouble. */
  696. X    NewItem = MakeNewItem(ptr, size, ALLOC_TYPE);
  697. X
  698. X    /* and add it to the list */
  699. X    AddTail(&ResList, NewItem);
  700. X    break;
  701. X
  702. X  case LOCK_MSG:
  703. X    /* lock resource type */
  704. X    NewItem = MakeNewItem(ptr, 0, LOCK_TYPE); /* size not used */
  705. X    AddTail(&ResList, &(NewItem->n));
  706. X    break;
  707. X
  708. X  case LIB_MSG:
  709. X    /* library opened */
  710. X    NewItem = MakeNewItem(ptr, 0, LIB_TYPE);
  711. X    AddTail(&ResList, &(NewItem->n));
  712. X    break;
  713. X
  714. X  case NEWSCREEN_MSG:
  715. X    NewItem = MakeNewItem(ptr, 0, SCREEN_TYPE);
  716. X    AddTail(&ResList, &(NewItem->n));
  717. X    break;
  718. X
  719. X  case NEWWINDOW_MSG:
  720. X    NewItem = MakeNewItem(ptr, 0, WINDOW_TYPE);
  721. X    AddTail(&ResList, &(NewItem->n));
  722. X    break;
  723. X
  724. X  case FREEONE_MSG:
  725. X    NonFatalError("FREEONE not implemented yet!  Bogosity, dude.\n");
  726. X    break;
  727. X
  728. X  case FREEALL_MSG:
  729. X    FreeAll(&ResList);
  730. X    break;
  731. X
  732. X  case DONE_MSG:  /* this is really cleaning up */
  733. X    while (node = (struct ResListItem *)RemTail(&ResList)) {
  734. X    /* this depends on the fact that &node = &NewItem->n */
  735. X    FreeResource(node);
  736. X    if (node) { 
  737. X          FreeMem(node, sizeof(struct ResListItem)); /* overhead */
  738. X          node = NULL;
  739. X          } /* if */
  740. X     }
  741. X   break;
  742. X  default:
  743. X   NonFatalError("CleanUp: unknown message: %ld\n", msg);
  744. X   break;
  745. X  } /* switch */
  746. X} /* CleanUp */
  747. X
  748. Xchar *Allocate(size)
  749. X  int size;
  750. X{
  751. X  char *ptr;
  752. X  extern char *AllocMem();
  753. X
  754. X/*  ptr = AllocMem(size, MEMF_CLEAR);*/
  755. X  ptr = mymalloc(size);
  756. X  if (ptr==NULL)
  757. X      FatalError("Out of memory!  Couldn't allocate %ld bytes\n", size);
  758. X/* already registered in mymalloc */
  759. X#if 0
  760. X  else CleanUp(ALLOC_MSG, ptr, size); /* register the resource */
  761. X#endif
  762. X  return(ptr);
  763. X}
  764. X
  765. X/* NonFatalError */
  766. Xvoid NonFatalError(s, a1, a2, a3, a4, a5)
  767. X char *s, *a1, *a2, *a3, *a4, *a5;
  768. X{
  769. Xfprintf(stderr, s, a1, a2, a3, a4, a5);
  770. X}
  771. X
  772. X/* prints error message string s (w/optional format strings) , cleans
  773. X   up and exits */
  774. Xvoid FatalError(s, a1, a2, a3, a4, a5)
  775. X char *s, *a1, *a2, *a3, *a4, *a5;
  776. X{
  777. X  fprintf(stderr, s, a1 ,a2, a3, a4, a5);
  778. X  CloseGraphics();
  779. X  CleanUp(DONE_MSG);
  780. X  exit(10);
  781. X}
  782. X
  783. X/* read the file into one enormous buffer */
  784. X/* returns 1 if successful, 0 if not      */
  785. X
  786. Xint readfile(name,thebuffer)
  787. X    char *name, **thebuffer;
  788. X{
  789. X  struct FileInfoBlock *fib;
  790. X  extern struct FileLock *Lock();
  791. X  struct FileLock *lock;
  792. X  struct FileHandle *fh;
  793. X  int filesize,success,bytesread;
  794. X
  795. X  /* fib must be longword aligned!!! */
  796. X  fib = (struct FileInfoBlock *)Allocate(sizeof(struct FileInfoBlock));
  797. X#ifdef DEBUG
  798. Xprintf("FileInfoBlock is at %d\n", fib);
  799. X#endif
  800. X  lock = Lock(name, ACCESS_READ);
  801. X  if (!lock) {
  802. X    NonFatalError("%s not found!\n", name);
  803. X    return 0;
  804. X    } /* if */
  805. X  /* Normally, we could call
  806. X     CleanUp(LOCK_MSG, (char *)lock, 0);
  807. X     to register the resource; but we'll just unlock after we're
  808. X     done so that the user can swap disks w/o trouble */
  809. X  success = Examine(lock, fib);
  810. X  if (!success) {
  811. X      NonFatalError("Couldn't examine %s!\n", name);
  812. X      UnLock(lock); /* we're done with the lock */
  813. X      return 0;
  814. X      }
  815. X
  816. X#ifdef DEBUG
  817. X/*---------------------------------------------------------------*/
  818. Xprintf("Name: %s\n", fib->fib_FileName);
  819. Xprintf("[%d] ", fib->fib_DirEntryType);
  820. Xif (fib->fib_DirEntryType>0) printf("Directory.\n");
  821. X else printf("Plain file.\n");
  822. Xprintf("file size in bytes:  %d\n", fib->fib_Size);
  823. Xprintf("          in blocks: %d\n", fib->fib_NumBlocks);
  824. Xprintf("file comment: %s\n", fib->fib_Comment);
  825. X/*printf("Last modified: \n"); ShowDate(&(fib->fib_Date));*/
  826. X/*---------------------------------------------------------------*/
  827. X#endif
  828. X
  829. X  filesize = fib->fib_Size; /* file size */
  830. X  UnLock(lock); /* we're done with the lock */
  831. X
  832. X  *thebuffer=Allocate(filesize+1); /* add a '\0' to end */
  833. X
  834. X  fh = Open(name, MODE_OLDFILE);
  835. X  if (!fh) {
  836. X    NonFatalError("Couldn't open %s\n", name);
  837. X    return 0;
  838. X    }
  839. X  bytesread = Read(fh, *thebuffer, filesize);
  840. X  if (bytesread != filesize) {
  841. X    FatalError("Couldn't read %ld bytes from %s\n",filesize,name);
  842. X    Close(fh);
  843. X    return 0;
  844. X    }
  845. X  (*thebuffer)[filesize] = '\0';
  846. X  Close(fh);
  847. X  return 1;
  848. X} /* readfile */
  849. X
  850. X/* count the number of lines that are separated by a newline in
  851. X   buffer */
  852. Xint countlines(buffer)
  853. X    char *buffer;
  854. X{
  855. X  int count=0, i=0;
  856. X  while (buffer[i]) if (buffer[i++]=='\n') count++;
  857. X  if (buffer[i-1] != '\n') count++; /* printf("No terminating newline\n");*/
  858. X   /*else printf("Terminating newline\n");*/
  859. X  return(count);
  860. X} /* countlines */
  861. X
  862. X/* returns 1 if s is in sl, 0 otherwise */
  863. Xint isin(sl, s)
  864. X   struct slist *sl;
  865. X   char *s;
  866. X{
  867. X  if (qstate.CaseSensitive) 
  868. X   while(sl) {
  869. X     if (!strcmp(sl->s, s)) return(1);
  870. X     sl=sl->next;
  871. X    } /* while */
  872. X  else 
  873. X   while(sl) {
  874. X     if (!stricmp(sl->s, s)) return(1);
  875. X     sl=sl->next;
  876. X    } /* while */
  877. X  return(0);
  878. X} /* isin */
  879. X
  880. X/* separate finds the ':' in a string "a:b" and replaces it with '\0'
  881. X   then return a pointer to b.  Modifies s. */
  882. Xchar *separate(s) char *s;
  883. X{
  884. X  while (*s) {
  885. X   if (*s==':') { *s = '\0'; return(s+1);}
  886. X   s++;
  887. X   } /* while */
  888. X  return(NULL); /* no ':' found */
  889. X} /* separate */
  890. X
  891. X/* q is the question string */
  892. Xvoid ask(q, sofar, total)
  893. X char *q; 
  894. X int sofar, total;
  895. X{
  896. X
  897. X printf("[%ld/%ld] %s: ", sofar, total, q); }
  898. X
  899. X/* a is answer string */
  900. Xvoid getinput(a) char *a; {
  901. X
  902. X gets(a); remwh(a); }
  903. X
  904. X/* if he gets it right */
  905. Xvoid correct() { printf("Right!\n"); }
  906. X
  907. X/* if wrong */
  908. Xvoid wrong(wrongi, right)
  909. X   struct slist *right;
  910. X   char *wrongi;
  911. X{
  912. X int num;
  913. X
  914. X/* if user just pressed return be nice; at least he admits his ignorance */
  915. Xif (*wrongi) printf("Wrong, dummy.  ");
  916. X num = slistSize(right);
  917. X if (num == 1) printf("\"%s\"\n", right->s);
  918. X else {
  919. X   printf("\n");
  920. X   while(right->next) printf("  \"%s\" or\n", right->s),right=right->next;
  921. X   printf("  \"%s\"\n",right->s);
  922. X   } /* else */
  923. X} /* wrong */
  924. X
  925. X/* extractlines finds n strings each separated by a '\n'.  Creates and
  926. X   fills an array that is the start address of each string.  Replaces
  927. X   '\n' with '\0' */
  928. Xchar **extractlines(n,bigbuf)
  929. X  int n;
  930. X  char *bigbuf;
  931. X{
  932. X  char **rtn;
  933. X  int i=0, j=0;
  934. X
  935. X  rtn = (char **)Allocate(n * sizeof(char *));
  936. X  rtn[0]=bigbuf;
  937. X  while (bigbuf[i]) { /* j is in case there's no terminating newline */
  938. X   if (bigbuf[i] == '\n') {
  939. X     rtn[++j] = &(bigbuf[i])+1;
  940. X     bigbuf[i] = '\0';
  941. X    } /* if */
  942. X   i++;
  943. X  } /* while */
  944. X
  945. X  return(rtn);
  946. X} /* extractlines */
  947. X
  948. X/* delete any blank lines in a buffer s */
  949. Xvoid deleteblanklines(s)
  950. X    char *s;
  951. X{
  952. X  char *t;
  953. X  t = s;
  954. X  /* get rid of any initial blank lines */
  955. X  while (*t == '\n') t++;
  956. X  while (1) {
  957. X    /* t now points to first char in a non-empty line */
  958. X    while (*t != '\n') {
  959. X      if (*t == '\0') {*s = '\0'; return;}
  960. X      *s++ = *t++;
  961. X      }
  962. X    while (*t == '\n') t++;
  963. X    *s++='\n'; /* put one in */
  964. X  } /* while 1 */
  965. X} /* deleteblanklines */
  966. X
  967. X/* add an int to an ilist */
  968. Xvoid ilistAdd(il, i)
  969. X    ilist *il;
  970. X    int i;
  971. X{
  972. X  while (il->next) il = il->next;
  973. X  il->next = (ilist *)Allocate(sizeof(ilist));
  974. X  (il->next)->i = i;
  975. X  (il->next)->next = NULL;
  976. X} /* ilistAdd */
  977. X
  978. X/* create and return a new ilist */
  979. Xilist *Makeilist(i) int i;
  980. X{
  981. X  ilist *rtn;
  982. X  rtn = (ilist *)Allocate(sizeof(ilist));
  983. X  rtn->i = i; rtn->next = NULL;
  984. X  return(rtn);
  985. X} /* Makeilist */
  986. X
  987. X/***
  988. X ***   This function should be called after a quiz file has been read
  989. X ***   in via readfile().  The file will be in buf at that time.
  990. X ***  
  991. X ***   ProcessQFile will delete blank lines, count lines, and parse
  992. X ***   them.  Note that all parameters are modified.  Chotto abunai ne.
  993. X ***
  994. X ***   *n is set to the number of lines.
  995. X ***   *answers, *questions, *score, *origorder are all allocated.
  996. X ***   A lot of other stuff will be allocated by subroutines.  When
  997. X ***   this quiz file is to be discarded, all allocated memory should
  998. X ***   be free via FreeAll().
  999. X ***
  1000. X ***   Answers and questions will be swapped if qstate.Switch.  A
  1001. X ***   random order is calculated as well.
  1002. X ***
  1003. X ***   Returns the number of questions.
  1004. X ***
  1005. X ***/
  1006. Xint ProcessQFile(answers, questions, score, origorder, preprocess, numq)
  1007. X  struct slist ***answers, ***questions;
  1008. X  short **score, **origorder;
  1009. X  int preprocess, numq;
  1010. X{
  1011. X  /***
  1012. X   *** lines contains pointers to the beginning each line of
  1013. X   *** the quiz file.
  1014. X   *** tmpans is used in extracting the answer from each line.
  1015. X   ***
  1016. X   ***/
  1017. X  char **lines,*tmpans;
  1018. X  int n,i; /* n is the number of questions */
  1019. X
  1020. X  /***
  1021. X   *** tmpslist and tmpptr are used for swapping
  1022. X   ***/
  1023. X  struct slist *tmpslist;
  1024. X  short tmpshort;
  1025. X  if (preprocess) {
  1026. X    deleteblanklines(buf);
  1027. X    n = countlines(buf);
  1028. X    lines = extractlines(n,buf);
  1029. X    if (qstate.GraphType = readscore(n)) cleargraph(),drawgraph();
  1030. X    UpdateMenuGraphState();
  1031. X    *answers = (struct slist **)Allocate(n * sizeof(struct slist *));
  1032. X    *questions = (struct slist **)Allocate(n * sizeof(struct slist *));
  1033. X    *score = (short *)Allocate(n * sizeof(short)); /* initializes to 0 */
  1034. X    *origorder = (short *)Allocate(n * sizeof(short));
  1035. X
  1036. X    history = *score; hindices = *origorder;
  1037. X    for (i=0; i<n; i++) {
  1038. X      (*origorder)[i]=(short)i;
  1039. X      /* now find the answer in "question:answer" line */
  1040. X      tmpans =  separate(lines[i]); /* modifies buf */
  1041. X
  1042. X      /* this error should really just abort this particular file
  1043. X         and not actually exit.  Later... */
  1044. X      if (!tmpans)
  1045. X        FatalError("Line \"%s\" is missing a colon\n", lines[i]);
  1046. X
  1047. X      (*questions)[i] = expand(lines[i]);
  1048. X      (*answers)[i] = expand(tmpans);
  1049. X
  1050. X    } /* for */
  1051. X
  1052. X    if (qstate.Switch) doswap(answers, questions);
  1053. X
  1054. X  } /* if preprocess */
  1055. X  else n = numq; /* if preprocess, n is passed in as last arg */
  1056. X
  1057. X  /* calculate a random order */
  1058. X  srand((unsigned)time(NULL)); /* time is in seconds; where's utime? */
  1059. X  for (i=0;i<n;i++) (*score)[i] = 0; /* can't be done in loop below */
  1060. X
  1061. X  for (i= 0; i<n; i++) {
  1062. X    int j, k;
  1063. X    /* swap questions j & k */
  1064. X    j=rand() % n; k = rand() % n;
  1065. X    if (j != k) {
  1066. X      tmpslist = (*questions)[j];
  1067. X      (*questions)[j] = (*questions)[k];
  1068. X      (*questions)[k] = tmpslist;
  1069. X
  1070. X      tmpslist = (*answers)[j];
  1071. X      (*answers)[j] = (*answers)[k];
  1072. X      (*answers)[k] = tmpslist;
  1073. X
  1074. X      tmpshort = (*origorder)[j];
  1075. X      (*origorder)[j] = (*origorder)[k];
  1076. X      (*origorder)[k] = tmpshort;
  1077. X      } /* if */
  1078. X    } /* for */
  1079. X  return(n);
  1080. X  } /* ProcessQFile */
  1081. X
  1082. X
  1083. Xvoid doswap(a,q)
  1084. X   struct slist ***a, ***q;
  1085. X{
  1086. X  struct slist **tmpptr;
  1087. X  tmpptr=*a;*a=*q;*q=tmpptr;
  1088. X} /* doswap */
  1089. X
  1090. Xvoid stractivate()
  1091. X{
  1092. X ActivateGadget(&sgadget, backwindow, NULL);
  1093. X} /* stractivate */
  1094. X
  1095. X/* swaps elements i and j of qs, as, ss, and os */
  1096. Xvoid MajorSwap(qs, as, ss, os, i, j)
  1097. X   short ss[], os[];
  1098. X   struct slist *as[], *qs[];
  1099. X   int i, j;
  1100. X{
  1101. X  short tmpshort;
  1102. X  struct slist *tmpslist;
  1103. X  
  1104. X  tmpslist = qs[i];
  1105. X  qs[i] = qs[j];
  1106. X  qs[j] = tmpslist;
  1107. X
  1108. X  tmpslist = as[i];
  1109. X  as[i] = as[j];
  1110. X  as[j] = tmpslist;
  1111. X
  1112. X  tmpshort = ss[i];
  1113. X  ss[i] = ss[j];
  1114. X  ss[j] = tmpshort;
  1115. X
  1116. X  tmpshort = os[i];
  1117. X  os[i] = os[j];
  1118. X  os[j] = tmpshort;
  1119. X} /* MajorSwap */
  1120. X
  1121. Xvoid quiz()
  1122. X {
  1123. X  /***
  1124. X   *** answers is a list of valid answers
  1125. X   *** questions--a list of valid questions
  1126. X   ***
  1127. X   *** tmpslist is used for swapping
  1128. X   ***
  1129. X   ***/
  1130. X  struct slist **answers, **questions;
  1131. X
  1132. X  /***
  1133. X   *** total is the total number of correct answers given.
  1134. X   *** n is the number of questions in the file.
  1135. X   *** gaveup = 1 if the user quits in the midde of this test.
  1136. X   ***   if this is the case, a score file will NOT be written
  1137. X   ***
  1138. X   ***/
  1139. X  int i=0,n=0,total=0,gaveup=0,j;
  1140. X
  1141. X  /* score is an array of shorts--one for each question.  Initially, 
  1142. X     score[i] = 0.  If the user answers a question right the first time,
  1143. X     score[i] = RIGHT.  If he gets it wrong, score is decremented and
  1144. X     the question is asked again later.  Each time he gets it wrong,
  1145. X     score[i] is decremented until score[i] == MAXWRONG.  If the user
  1146. X     gets it right, score[i] = -score[i] and thus tells how many times it
  1147. X     took to get it right. */
  1148. X
  1149. X  /***
  1150. X   *** origorder[n] is a list of shorts that gives the original index
  1151. X   *** of each quiz line.  Remember, these get shuffled around since
  1152. X   *** a random order is selected, and missed questions get stuck at
  1153. X   *** the end.
  1154. X   ***
  1155. X   ***/
  1156. X  short *score, *origorder;
  1157. X  ULONG val;
  1158. X
  1159. X  /* initialize values */
  1160. X  fileinit:
  1161. X  i=0,n=0,total=0,gaveup=0,val=IGNORE;
  1162. X
  1163. X  strcpy(sStringInfo.Buffer, "");
  1164. X  sStringInfo.BufferPos = 0;
  1165. X  sStringInfo.DispPos = 1;
  1166. X
  1167. X  /* if we are in an asking state, process the question file */
  1168. X  if (qstate.Asking)
  1169. X     n = ProcessQFile(&answers, &questions, &score, &origorder, 1, 0);
  1170. X
  1171. X
  1172. X  qtext = NULL; atext = NULL; ctext = NULL;
  1173. X  if (qstate.Asking)
  1174. X   {
  1175. X     qtext = questions[i]->s;
  1176. X    /* DrawQText();  necessary? we call redraw */
  1177. X   }
  1178. X
  1179. X UpdateCurrentQ(0, (int)origorder[i]);
  1180. X redraw();
  1181. X stractivate();
  1182. X
  1183. X/* main loop */
  1184. Xquizloop:
  1185. Xwhile ((i<n)||(!qstate.Asking)) {
  1186. X WaitPort(backwindow->UserPort); /* be nice */
  1187. X while (mes = GetMsg(backwindow->UserPort)) val=bhandlemsg(mes);
  1188. X switch (val) {
  1189. X  case QUITNOW:
  1190. X   return; /* quit */
  1191. X
  1192. X  case ABORTNOW:
  1193. X   val = IGNORE;
  1194. X   OnMenu(backwindow, BEGINMENUNUM);
  1195. X   qstate.Asking = 0;
  1196. X   qstate.ShowingAns = 0;
  1197. X   qtext = NULL;
  1198. X
  1199. X   strcpy(sStringInfo.Buffer, "");
  1200. X   sStringInfo.BufferPos = 0;
  1201. X   sStringInfo.DispPos = 1;
  1202. X   redraw();
  1203. X   stractivate();
  1204. X   break;
  1205. X   /* abort */
  1206. X
  1207. X case OPENNEWFILE:
  1208. X   val=IGNORE;
  1209. X   qstate.Asking=1;
  1210. X   OffMenu(backwindow, BEGINMENUNUM);
  1211. X   goto fileinit; /* filename already set */
  1212. X
  1213. X case SWITCHEM:
  1214. X  doswap(&answers, &questions);
  1215. X  if (qstate.Asking) {
  1216. X    qtext = questions[i]->s;
  1217. X    DrawQText();
  1218. X   } /* if */
  1219. X   break; /* if switchem */
  1220. X
  1221. X case STARTASKING:
  1222. X if ((!qstate.Asking) && qstate.File[0]) {
  1223. X    qstate.Asking = 1;
  1224. X        i=0,total=0,gaveup=0,val=IGNORE;
  1225. X        OffMenu(backwindow, BEGINMENUNUM);
  1226. X        ProcessQFile(&answers, &questions, &score, &origorder, 0, n);
  1227. X        qtext = questions[i]->s;
  1228. X        UpdateCurrentQ(currentquestion, (int)origorder[i]);
  1229. X        DrawQText();
  1230. X        if (qstate.GraphType) drawgraph();
  1231. X        stractivate();
  1232. X  } /* if */
  1233. X  break; /* STARTASKING */
  1234. X
  1235. X case NEWSTRING:
  1236. X  if (qstate.Asking) {
  1237. X    remwh(atext);
  1238. X    if (isin(answers[i], atext)) {
  1239. X      /* correct();*/
  1240. X       if (score[i]==0) score[i] = RIGHT,total++;
  1241. X       else score[i] = -score[i];
  1242. X       if (qstate.ShowingAns) {
  1243. X         qstate.ShowingAns = 0;
  1244. X         EraseCText();
  1245. X         } /* if */
  1246. X      } /* if isin */
  1247. X
  1248. X    else { /* got this one wrong */
  1249. X    /* wrong(atext,answers[i]);*/
  1250. X     score[i]--;
  1251. X     if (score[i] <= MAXWRONG) {
  1252. X        i++;
  1253. X        ctext = NULL;
  1254. X        qstate.ShowingAns = 0;
  1255. X        EraseCText();
  1256. X        if (i>=n) break;
  1257. X        else
  1258. X         { /* do next question */
  1259. X          qtext = questions[i]->s;
  1260. X          DrawQText();
  1261. X          strcpy(sStringInfo.Buffer, "");
  1262. X          sStringInfo.BufferPos = 0;
  1263. X          sStringInfo.DispPos = 1;
  1264. X          RefreshGadgets(&sgadget, backwindow, NULL);
  1265. X          stractivate();
  1266. X          UpdateCurrentQ(currentquestion, (int)origorder[i]);
  1267. X          continue;
  1268. X         } /* else */
  1269. X
  1270. X     } /* give up on this question */
  1271. X     else  {
  1272. X       ctext = answers[i]->s; /* use the first legal answer I guess */
  1273. X       qstate.ShowingAns = 1;
  1274. X       DrawCText();
  1275. X       } /* else */
  1276. X
  1277. X     /* we want to ask again, so put the question back */
  1278. X     /* swap with the last element */
  1279. X     MajorSwap(questions, answers, score, origorder, i, n-1);
  1280. X     i--;
  1281. X     
  1282. X     } /* else wrong */
  1283. X
  1284. X    strcpy(sStringInfo.Buffer, "");
  1285. X    sStringInfo.BufferPos = 0;
  1286. X    sStringInfo.DispPos = 1;
  1287. X    i++;
  1288. X    if (i>=n) break;
  1289. X    qtext = questions[i]->s;
  1290. X    DrawQText();
  1291. X    UpdateCurrentQ(currentquestion, (int)origorder[i]);
  1292. X
  1293. X    } /* if asking */
  1294. X   break; /* if a new string */
  1295. X
  1296. X  case DISPLAYQ:
  1297. X   if (qstate.Asking) {
  1298. X     int theq=-1;
  1299. X     /* so we want to swap the current question with newquestion */
  1300. X     /* newquestion refers to the original order, so we have to find */
  1301. X     /* it first */
  1302. X     for (j=0; j<n; j++) if (origorder[j]==newquestion) theq=j;
  1303. X     if (theq==-1) {
  1304. X         NonFatalError("Couldn't find that question out of %d!\n",n);
  1305. X         break; /* from switch */
  1306. X         } /* if */
  1307. X
  1308. X     if (i== theq) break;
  1309. X     /* if theq<i, then we already asked this question and should decrement
  1310. X        i so that we don't lose any new questions */
  1311. X     if (theq<i) i--;
  1312. X     MajorSwap(questions, answers, score, origorder, i, theq);
  1313. X     qtext = questions[i]->s;
  1314. X
  1315. X     UpdateCurrentQ(currentquestion,(int)origorder[i]);
  1316. X
  1317. X     strcpy(sStringInfo.Buffer, "");
  1318. X     sStringInfo.BufferPos = 0;
  1319. X     sStringInfo.DispPos = 1;
  1320. X
  1321. X     redraw();
  1322. X     stractivate();
  1323. X
  1324. X   } /* if asking */
  1325. X   break; /* DISPLAYQ */
  1326. X  case IGNORE:
  1327. X   break;
  1328. X  default:
  1329. X   NonFatalError("quiz(): %d is an unknown message\n", val);
  1330. X   break;
  1331. X  } /* switch val */
  1332. X  
  1333. X stractivate();
  1334. X RefreshGadgets(&sgadget, backwindow, NULL);
  1335. X
  1336. X val=IGNORE;
  1337. X} /* while i<=n */
  1338. X
  1339. X  qstate.Asking = 0;
  1340. X  qstate.ShowingAns = 0;
  1341. X  qtext = NULL; /* so it won't be redraw()n */
  1342. X  OnMenu(backwindow, BEGINMENUNUM);
  1343. X  strcpy(sStringInfo.Buffer, "");
  1344. X  sStringInfo.BufferPos = 0;
  1345. X  sStringInfo.DispPos = 1;
  1346. X  RefreshGadgets(&sgadget, backwindow, NULL);
  1347. X  stractivate();
  1348. X
  1349. X  if (total != n) {
  1350. X    printf("You missed:\n");
  1351. X    for (i=0;i<n;i++)
  1352. X      /* score[i] is 0 if "quit" was selected */
  1353. X      if ((score[i] != RIGHT)&&(score[i] != 0))
  1354. X        printf("  %s: %s\n",questions[i]->s,answers[i]->s);
  1355. X    } /* if total != n */
  1356. X  else printf("Congratulations!\n");
  1357. X  printf("\nScore: %ld/%ld (%ld%%)\n", total, n, total * 100 / n);
  1358. X  if (gaveup==0){
  1359. X     writescore(score, n, origorder, total);
  1360. X     if (qstate.GraphType==0) { 
  1361. X        qstate.GraphType = BYQUESTION;
  1362. X        UpdateMenuGraphState();
  1363. X/*        OffMenu(backwindow, (SHIFTMENU(1)|SHIFTITEM(4)|SHIFTSUB(NOSUB)));
  1364. X        OnMenu(backwindow, (SHIFTMENU(1)|SHIFTITEM(3)|SHIFTSUB(NOSUB)));*/
  1365. X       } /* if */
  1366. X     } /* if */
  1367. X  if (qstate.GraphType) {cleargraph(); drawgraph();}
  1368. X  i = 0;
  1369. X  EraseQText(); EraseCText(); /* does nothing if they are empty */
  1370. X  goto quizloop;
  1371. X} /* quiz */
  1372. X
  1373. X/* write the score to filename.sc, also updates graph data */
  1374. Xvoid writescore(score, n, value, total)
  1375. X    short *score, *value;
  1376. X    int n, total;
  1377. X{
  1378. X  char scorefile[MAXFILENAME+3]; /* ".sc" */
  1379. X  FILE *fh;
  1380. X  int i, worstq;
  1381. X  strcpy(scorefile,qstate.File); strcat(scorefile,SCORE_FILE_EXT);
  1382. X  fh = fopen(scorefile,"a");
  1383. X  if (fh==NULL) NonFatalError("Couldn't open score file %s\n",scorefile);
  1384. X  else {
  1385. X    int *intptr;
  1386. X    intptr = AddTrial(n-total,n);
  1387. X
  1388. X    worstq = intptr[0];
  1389. X    for (i=0;i<n;i++) {
  1390. X/*printf("%d: orig=%d trialdata[%d]=%d worst=%d\n",
  1391. X    i,value[i],value[i],intptr[value[i]],worstq);*/
  1392. X      if (score[i] != RIGHT) {
  1393. X        fprintf(fh, "%d ", value[i]);
  1394. X        intptr[value[i]]++;
  1395. X        } /* if */
  1396. X      if (intptr[value[i]] > worstq) worstq = intptr[value[i]];
  1397. X      } /* for */
  1398. X    fprintf(fh, "\n");
  1399. X    fclose(fh);
  1400. X    /* only set worst question if he actually missed something */
  1401. X    if (n-total) SetWorstQuestion(worstq);
  1402. X    } /* else */
  1403. X
  1404. X} /* writescore */
  1405. X
  1406. Xvoid main(argc, argv)
  1407. X  int argc;
  1408. X  union {
  1409. X           char **args;
  1410. X           struct WBStartup *msg; 
  1411. X         } argv;
  1412. X{
  1413. X
  1414. X  CleanUp(INIT_MSG);        /* initialize resource manager */
  1415. X
  1416. X  qstate.Switch = 0;
  1417. X  qstate.File[0] = '\0';
  1418. X  qstate.ShowingAns = 0;
  1419. X  qstate.CaseSensitive = 1;
  1420. X  qstate.Asking = 0;
  1421. X  qstate.GraphType = 0;
  1422. X
  1423. X  parseargs(argc, &argv);
  1424. X
  1425. X  if (qstate.File[0]) {
  1426. X    if (readfile(qstate.File,&buf))
  1427. X       qstate.Asking = 1;
  1428. X    else strcpy(qstate.File, "");
  1429. X    } /* if */
  1430. X
  1431. X  InitGraphics();
  1432. X  redraw();
  1433. X
  1434. X  quiz();
  1435. X  CloseGraphics();
  1436. X  CleanUp(DONE_MSG);
  1437. X  exit(0);
  1438. X} /* main */
  1439. END_OF_FILE
  1440. if test 26723 -ne `wc -c <'quiz.c'`; then
  1441.     echo shar: \"'quiz.c'\" unpacked with wrong size!
  1442. fi
  1443. # end of 'quiz.c'
  1444. fi
  1445. if test -f 'screen.c' -a "${1}" != "-c" ; then 
  1446.   echo shar: Will not clobber existing file \"'screen.c'\"
  1447. else
  1448. echo shar: Extracting \"'screen.c'\" \(17829 characters\)
  1449. sed "s/^X//" >'screen.c' <<'END_OF_FILE'
  1450. X#include <stdio.h>
  1451. X#include <string.h> /* strcpy */
  1452. X#include "screen.h"
  1453. X
  1454. Xvoid DrawRaisedText();
  1455. Xvoid EraseQText(), EraseCText();
  1456. Xvoid DrawQText(), DrawCText();
  1457. Xvoid colorwindow();
  1458. Xint OpenLibs();
  1459. Xvoid InitGraphics();
  1460. Xvoid UpdateMenuGraphState();
  1461. Xvoid CloseGraphics();
  1462. XULONG ehandlemsg();
  1463. Xint handlegadget();
  1464. Xint handlebuttons();
  1465. Xint bhandlemsg();
  1466. Xint handlemenu();
  1467. Xvoid main();
  1468. Xvoid redraw();
  1469. Xvoid about(), abort();
  1470. Xint load();
  1471. X
  1472. Xextern void stractivate();             /* quiz.c  */
  1473. X
  1474. Xextern void drawgraph(), cleargraph(); /* graph.c */
  1475. Xextern int whichquestion();            /* graph.c */
  1476. X
  1477. X
  1478. X/* draw semi-3d-looking text */
  1479. Xvoid DrawRaisedText(rp,text,slen,x,y)
  1480. X struct RastPort *rp;
  1481. X  char *text;
  1482. X  int slen, x, y;
  1483. X {
  1484. X    /* draw it dark */
  1485. X     SetAPen(rp, GREY2);
  1486. X     Move(rp, x+1,y);
  1487. X     Text(rp, text, slen);
  1488. X
  1489. X     /* draw it light */
  1490. X     SetAPen(rp, GREY11);
  1491. X     Move(rp, x-1,y);
  1492. X     Text(rp, text, slen);
  1493. X
  1494. X     /* draw it just right */
  1495. X     SetAPen(rp, GREY7);
  1496. X     Move(rp, x,y);
  1497. X     Text(rp, text, slen);
  1498. X} /* DrawRaisedText */
  1499. X
  1500. X/* clear qtext display area */
  1501. Xvoid EraseQText() {
  1502. X  if (qpb[0])
  1503. X   { /* clear area */
  1504. X   SetAPen(rp, GREY7);
  1505. X   SetDrMd(rp, JAM1);
  1506. X   RectFill(rp, qpt[2], qpt[3], qpb[2], qpb[3]);
  1507. X   qpb[0] = 0;
  1508. X   } /* if */
  1509. X} /* EraseQText */
  1510. X
  1511. X#define QCOLOR GREY3
  1512. X/* draw the question */
  1513. Xvoid DrawQText() 
  1514. X{
  1515. X  int slen,theight,textsize;
  1516. X
  1517. X  /* delete old border */
  1518. X  if (qpb[0]) /* don't delete if first time */
  1519. X    {
  1520. X    /* clear the area */
  1521. X    SetAPen(rp, GREY7);
  1522. X    SetDrMd(rp, JAM1);
  1523. X    RectFill(rp, qpt[2], qpt[3], qpb[2], qpb[3]);
  1524. X    } /* if */
  1525. X  slen = strlen(qtext);
  1526. X  if (slen==0) return;
  1527. X  theight = rp->TxHeight;
  1528. X  textsize = slen * rp->TxWidth + 1; /* 1 pixel pad? */
  1529. X  qpt[0] = QX-BORDWIDTH*2;
  1530. X  qpt[1] = QY+theight+BORDWIDTH*2;
  1531. X  qpt[2] = QX-BORDWIDTH*2;
  1532. X  qpt[3] = QY-BORDWIDTH*2;
  1533. X  qpt[4] = QX+textsize+BORDWIDTH*2;
  1534. X  qpt[5] = QY-BORDWIDTH*2;
  1535. X
  1536. X  qpb[0] = QX-BORDWIDTH*2;
  1537. X  qpb[1] = QY+theight+BORDWIDTH*2;
  1538. X  qpb[2] = QX+textsize+BORDWIDTH*2;
  1539. X  qpb[3] = QY+theight+BORDWIDTH*2;
  1540. X  qpb[4] = QX+textsize+BORDWIDTH*2;
  1541. X  qpb[5] = QY-BORDWIDTH*2;
  1542. X
  1543. X  if (slen <= maxqchars) {
  1544. X     /* set border */
  1545. X     DrawBorder(rp,&qtop,0,0);
  1546. X     /* draw black box */
  1547. X     SetAPen(rp, QCOLOR);
  1548. X     SetDrMd(rp, JAM1);
  1549. X     RectFill(rp, qpt[2]+BORDWIDTH, qpt[3]+BORDWIDTH,
  1550. X                  qpb[2]-BORDWIDTH, qpb[3]-BORDWIDTH);
  1551. X     /* now draw text */
  1552. X     DrawRaisedText(rp, qtext, slen, QX, QY+baseheight);
  1553. X     } /* if */
  1554. X  else { /* must make bigger window */
  1555. X     char *lastspace = NULL, *s, *r;
  1556. X     int done = 0, numlines = 0, maxlen = 0, i;
  1557. X     /* Have to copy strings and output them after breaking up */
  1558. X     /* qtext.  We must know maxlen's value in order to draw   */
  1559. X     /* the dark grey rectangle                                */
  1560. X     char brokentext[MAXLINES][MAXQCHARS];
  1561. X     int sizes[MAXLINES];
  1562. X     r = qtext;
  1563. X
  1564. X     do {
  1565. X       numlines++;
  1566. X       s = r;
  1567. X       while (s<r+maxqchars) {
  1568. X        if (*s == ' ') lastspace = s;
  1569. X        else if (*s == '\0') {done = 1; break;}
  1570. X        s++;
  1571. X        } /* while */
  1572. X      /* this is gross */
  1573. X      /* we found a line */
  1574. X      if (lastspace) {
  1575. X        if (!done) *lastspace = '\0'; /* gulp */
  1576. X        slen = strlen(r); if (slen>maxlen) maxlen = slen;
  1577. X        strncpy(brokentext[numlines-1],r,slen);
  1578. X        sizes[numlines-1] = slen;
  1579. X        /*DrawRaisedText(rp, r, slen, QX, QY+baseheight+theight*(numlines-1));*/
  1580. X        if (!done) *lastspace = ' ';
  1581. X        r = lastspace + 1;
  1582. X        while (*r == ' ') r++; /* skip over any more spaces */
  1583. X        if (!*r) done = 1;
  1584. X        lastspace = NULL;
  1585. X        } /* if lastspace */
  1586. X      else if (done) /* reached the end in this iteration */
  1587. X       {
  1588. X        slen = strlen(r); if (slen>maxlen) maxlen = slen;
  1589. X        strncpy(brokentext[numlines-1],r,slen);
  1590. X        sizes[numlines-1] = slen;
  1591. X        /*DrawRaisedText(rp, r, slen, QX, QY+baseheight+theight*(numlines-1));*/
  1592. X       }
  1593. X      else { /* no breaks */
  1594. X        strncpy(brokentext[numlines-1],r,maxqchars);
  1595. X        sizes[numlines-1] = maxqchars;
  1596. X        /*DrawRaisedText(rp, r, maxqchars, QX, QY+baseheight+theight*(numlines-1));*/
  1597. X        r+=maxqchars; maxlen = maxqchars;
  1598. X        while (*r == ' ') r++; /* skip over any more spaces */
  1599. X        if (!*r) done = 1;
  1600. X        } /* else */
  1601. X    } while ((!done)&&(numlines<MAXLINES));
  1602. X     /* set border -- only 3 must be changed*/
  1603. X     textsize = maxlen * rp->TxWidth + 1; /* 1 pixel pad? */
  1604. X
  1605. X     qpt[4] = QX+textsize+BORDWIDTH;
  1606. X     qpb[2] = QX+textsize+BORDWIDTH;
  1607. X     qpb[4] = QX+textsize+BORDWIDTH;
  1608. X
  1609. X     qpt[1] = QY+theight*numlines+BORDWIDTH;
  1610. X     qpb[1] = QY+theight*numlines+BORDWIDTH;
  1611. X     qpb[3] = QY+theight*numlines+BORDWIDTH;
  1612. X
  1613. X     DrawBorder(rp,&qtop,0,0);
  1614. X     /* draw black box */
  1615. X     SetAPen(rp, QCOLOR);
  1616. X     SetDrMd(rp, JAM1);
  1617. X     RectFill(rp, qpt[2]+BORDWIDTH, qpt[3]+BORDWIDTH,
  1618. X                  qpb[2]-BORDWIDTH, qpb[3]-BORDWIDTH);
  1619. X
  1620. X    /* now actually draw the text */
  1621. X    for (i=0;i<numlines;i++)
  1622. X     DrawRaisedText(rp, brokentext[i], sizes[i], QX, QY+baseheight+theight*i);
  1623. X  } /* else */
  1624. X} /* DrawQText */
  1625. X
  1626. X/* clear ctext display area */
  1627. Xvoid EraseCText() {
  1628. X  if (cpb[0])
  1629. X   { /* clear area */
  1630. X   SetAPen(rp, GREY7);
  1631. X   SetDrMd(rp, JAM1);
  1632. X   RectFill(rp, cpt[2], cpt[3], cpb[2], cpb[3]);
  1633. X   cpb[0] = 0;
  1634. X   } /* if */
  1635. X} /* EraseCText */
  1636. X
  1637. X#define CCOLOR 15 /* ? */
  1638. X/* draw the correct answer */
  1639. Xvoid DrawCText()
  1640. X{
  1641. X  int slen, theight, textsize;
  1642. X  /* delete old border if existing */
  1643. X  if (cpb[0])
  1644. X   { /* clear area */
  1645. X   SetAPen(rp, GREY7);
  1646. X   SetDrMd(rp, JAM1);
  1647. X   RectFill(rp, cpt[2], cpt[3], cpb[2], cpb[3]);
  1648. X   } /* if */
  1649. X  if (ctext==NULL) return;
  1650. X  slen = strlen(ctext);
  1651. X  if (slen==0) return;
  1652. X  theight = rp->TxHeight;
  1653. X  textsize = slen * rp->TxWidth + 1; /* 1 pixel pad? */
  1654. X
  1655. X  cpt[0] = CX-BORDWIDTH*2;
  1656. X  cpt[1] = CY+theight+BORDWIDTH*2;
  1657. X  cpt[2] = CX-BORDWIDTH*2;
  1658. X  cpt[3] = CY-BORDWIDTH*2;
  1659. X  cpt[4] = CX+textsize+BORDWIDTH*2;
  1660. X  cpt[5] = CY-BORDWIDTH*2;
  1661. X
  1662. X  cpb[0] = CX-BORDWIDTH*2;
  1663. X  cpb[1] = CY+theight+BORDWIDTH*2;
  1664. X  cpb[2] = CX+textsize+BORDWIDTH*2;
  1665. X  cpb[3] = CY+theight+BORDWIDTH*2;
  1666. X  cpb[4] = CX+textsize+BORDWIDTH*2;
  1667. X  cpb[5] = CY-BORDWIDTH*2;
  1668. X
  1669. X  if (slen <= maxqchars) {
  1670. X     /* set border */
  1671. X     DrawBorder(rp,&ctop,0,0);
  1672. X     /* draw black box */
  1673. X     SetAPen(rp, CCOLOR);
  1674. X     SetDrMd(rp, JAM1);
  1675. X     RectFill(rp, cpt[2]+BORDWIDTH, cpt[3]+BORDWIDTH,
  1676. X                  cpb[2]-BORDWIDTH, cpb[3]-BORDWIDTH);
  1677. X     /* now draw text */
  1678. X     DrawRaisedText(rp, ctext, slen, CX, CY+baseheight);
  1679. X     } /* if */
  1680. X    else { /* must make bigger window */
  1681. X     char *lastspace = NULL, *s, *r;
  1682. X     int done = 0, numlines = 0, maxlen = 0, i;
  1683. X     /* Have to copy strings and output them after breaking up */
  1684. X     /* ctext.  We must know maxlen's value in order to draw   */
  1685. X     /* the dark grey rectangle                                */
  1686. X     char brokentext[MAXLINES][MAXQCHARS];
  1687. X     int sizes[MAXLINES];
  1688. X     r = ctext;
  1689. X
  1690. X     do {
  1691. X       numlines++;
  1692. X       s = r;
  1693. X       while (s<r+maxqchars) {
  1694. X        if (*s == ' ') lastspace = s;
  1695. X        else if (*s == '\0') {done = 1; break;}
  1696. X        s++;
  1697. X        } /* while */
  1698. X      /* this is gross */
  1699. X      /* we found a line */
  1700. X      if (lastspace) {
  1701. X        if (!done) *lastspace = '\0'; /* gulp */
  1702. X        slen = strlen(r); if (slen>maxlen) maxlen = slen;
  1703. X        strncpy(brokentext[numlines-1],r,slen);
  1704. X        sizes[numlines-1] = slen;
  1705. X        if (!done) *lastspace = ' ';
  1706. X        r = lastspace + 1;
  1707. X        while (*r == ' ') r++; /* skip over any more spaces */
  1708. X        if (!*r) done = 1;
  1709. X        lastspace = NULL;
  1710. X        } /* if lastspace */
  1711. X      else if (done) /* reached the end in this iteration */
  1712. X       {
  1713. X        slen = strlen(r); if (slen>maxlen) maxlen = slen;
  1714. X        strncpy(brokentext[numlines-1],r,slen);
  1715. X        sizes[numlines-1] = slen;
  1716. X       }
  1717. X      else { /* no breaks */
  1718. X        strncpy(brokentext[numlines-1],r,maxqchars);
  1719. X        sizes[numlines-1] = maxqchars;
  1720. X        r+=maxqchars; maxlen = maxqchars;
  1721. X        while (*r == ' ') r++; /* skip over any more spaces */
  1722. X        if (!*r) done = 1;
  1723. X        } /* else */
  1724. X    } while ((!done)&&(numlines<MAXLINES));
  1725. X     /* set border -- only 3 must be changed*/
  1726. X     textsize = maxlen * rp->TxWidth + 1; /* 1 pixel pad? */
  1727. X
  1728. X     cpt[4] = CX+textsize+BORDWIDTH;
  1729. X     cpb[2] = CX+textsize+BORDWIDTH;
  1730. X     cpb[4] = CX+textsize+BORDWIDTH;
  1731. X
  1732. X     cpt[1] = CY+theight*numlines+BORDWIDTH;
  1733. X     cpb[1] = CY+theight*numlines+BORDWIDTH;
  1734. X     cpb[3] = CY+theight*numlines+BORDWIDTH;
  1735. X
  1736. X     DrawBorder(rp,&ctop,0,0);
  1737. X     /* draw black box */
  1738. X     SetAPen(rp, CCOLOR);
  1739. X     SetDrMd(rp, JAM1);
  1740. X     RectFill(rp, cpt[2]+BORDWIDTH, cpt[3]+BORDWIDTH,
  1741. X                  cpb[2]-BORDWIDTH, cpb[3]-BORDWIDTH);
  1742. X
  1743. X    /* now actually draw the text */
  1744. X    for (i=0;i<numlines;i++)
  1745. X     DrawRaisedText(rp, brokentext[i], sizes[i], CX, CY+baseheight+theight*i);
  1746. X  } /* else */
  1747. X} /* DrawCText */
  1748. X
  1749. X/* fills in an entire window with color c */
  1750. Xvoid colorwindow(w,c)
  1751. X  struct Window *w;
  1752. X  int c;
  1753. X{
  1754. X  SetDrMd(w->RPort, JAM1);
  1755. X  SetAPen(w->RPort, c);
  1756. X  RectFill(w->RPort, 0, 0, w->Width, w->Height);
  1757. X} /* colorwindow*/
  1758. X
  1759. X#if 0
  1760. Xvoid FatalError(s) char *s;
  1761. X{
  1762. X printf("%s", s);
  1763. X CloseGraphics();
  1764. X exit(1);
  1765. X} /* FatalError */
  1766. X#endif
  1767. X
  1768. X/* Just opens intuition library.  Returns 1 if successful, 0 if not */
  1769. Xint iopen=0, gopen=0;
  1770. Xint OpenLibs() {    
  1771. X  IntuitionBase = (struct IntuitionBase *)
  1772. X    OpenLibrary("intuition.library", 0);
  1773. X  if (IntuitionBase==NULL) return(0);
  1774. X  iopen = 1;
  1775. X  GfxBase = (struct GfxBase *)
  1776. X    OpenLibrary("graphics.library", 0);
  1777. X  if (GfxBase==NULL) return(0);
  1778. X  gopen=1;
  1779. X  return(1);
  1780. X  } /* OpenLibs */
  1781. X
  1782. Xvoid InitGraphics() {
  1783. X if (OpenLibs()==0) FatalError("Couldn't open libraries!\n");
  1784. X
  1785. X if ((qscreen = OpenScreen(&ns)) == NULL)
  1786. X   FatalError("Couldn't open screen!\n");
  1787. X vp = &(qscreen->ViewPort);
  1788. X
  1789. X /* initialize colortable */
  1790. X LoadRGB4(vp, &mycmap[0], 32);
  1791. X
  1792. X/* errnw.Screen  = qscreen;*/
  1793. X backnw.Screen = qscreen;
  1794. X
  1795. X backnw.FirstGadget = &sgadget;
  1796. X if ((backwindow = OpenWindow(&backnw)) == NULL)
  1797. X   FatalError("Couldn't open backdrop window!\n");
  1798. X/* if ((ewindow = OpenWindow(&errnw)) == NULL)
  1799. X   FatalError("Couldn't open error window!\n");*/
  1800. X
  1801. X menustrip[0] = &m1;
  1802. X menustrip[1] = &m2;
  1803. X menustrip[0]->NextMenu = menustrip[1];
  1804. X SetMenuStrip(backwindow,menustrip[0]);
  1805. X  
  1806. X if (qstate.Asking || (!qstate.File[0]))
  1807. X   OffMenu(backwindow, BEGINMENUNUM);
  1808. X if (qstate.GraphType==BYTRIAL) {
  1809. X   OffMenu(backwindow, TRIALMENUNUM);
  1810. X   OnMenu(backwindow, QUESTMENUNUM);
  1811. X   } /* if */
  1812. X else if (qstate.GraphType==BYQUESTION) 
  1813. X {
  1814. X   OffMenu(backwindow, QUESTMENUNUM);
  1815. X   OnMenu(backwindow, TRIALMENUNUM);
  1816. X   } /* if */
  1817. X ShowTitle(qscreen, FALSE);
  1818. X rp = backwindow->RPort;
  1819. X
  1820. X /* calculate how many characters can fit in one line of text */
  1821. X /* note that this method doesn't account for variable-width fonts :-( */
  1822. X maxqchars = (MAXQX-QX)/rp->TxWidth;
  1823. X baseheight = rp->TxBaseline;
  1824. X } /* InitGraphics */
  1825. X
  1826. X/* This is not very clean, but we need to be able to turn off/on the
  1827. X   correct menu items depending of the state of the graph */
  1828. Xvoid UpdateMenuGraphState() {
  1829. X if (qstate.GraphType==BYTRIAL) {
  1830. X   OffMenu(backwindow, TRIALMENUNUM);
  1831. X   OnMenu(backwindow, QUESTMENUNUM);
  1832. X } /* if */
  1833. X else if (qstate.GraphType == BYQUESTION) {
  1834. X   OffMenu(backwindow, QUESTMENUNUM);
  1835. X   OnMenu(backwindow, TRIALMENUNUM);
  1836. X } /* if */
  1837. X} /* UpdateMenuGraphState */
  1838. X
  1839. Xvoid CloseGraphics()
  1840. X{
  1841. X  if (backwindow) {
  1842. X    ClearMenuStrip(backwindow);
  1843. X    while (mes = GetMsg(backwindow->UserPort)) ReplyMsg(mes);
  1844. X    CloseWindow(backwindow);
  1845. X  } /* if backwindow */
  1846. X  if (qscreen) CloseScreen(qscreen);
  1847. X  if (gopen) CloseLibrary(GfxBase);
  1848. X  if (iopen) CloseLibrary(IntuitionBase);
  1849. X  /*OpenWorkBench();*/
  1850. X  /*WBenchToFront();*/
  1851. X} /* CloseGraphics */
  1852. X
  1853. XULONG ehandlemsg(message)
  1854. X   struct IntuiMessage *message;
  1855. X{
  1856. X  struct IntuiMessage localms;
  1857. X  int i;
  1858. X  UBYTE *s, *d;
  1859. X  ULONG class,code;
  1860. X
  1861. X  s = (UBYTE *)message;
  1862. X  d = (UBYTE *)&localms;
  1863. X
  1864. X  for (i=0;i<sizeof(struct IntuiMessage);i++) *d++=*s++;
  1865. X  ReplyMsg(message);
  1866. X    
  1867. X  class = localms.Class;
  1868. X  code = localms.Code;
  1869. X  switch (class)
  1870. X   {
  1871. X     case CLOSEWINDOW:
  1872. X        break;
  1873. X     case REFRESHWINDOW:
  1874. X     case NEWSIZE:
  1875. X       redraw();
  1876. X     default:
  1877. X       break;
  1878. X   } /* switch */
  1879. X   return(class);
  1880. X} /* ehandlemsg */
  1881. X
  1882. Xint handlegadget(g)
  1883. X   struct Gadget *g;
  1884. X{
  1885. X  switch (g->GadgetID) {
  1886. X    case STRINGID:
  1887. X      atext = ((struct StringInfo *)(g->SpecialInfo))->Buffer;
  1888. X      /*DrawQText();*/
  1889. X      return(NEWSTRING);
  1890. X      break;
  1891. X    case IMAGEID:
  1892. X      break;
  1893. X    default:
  1894. X      break;
  1895. X    }
  1896. X     return(IGNORE);
  1897. X
  1898. X} /* handle gadget */
  1899. X
  1900. Xvoid about() { printf("Quiz by Curtis Eubanks\n"); }
  1901. X
  1902. X/* returns 1 if successful, 0 if not */
  1903. Xint load() { 
  1904. X  if (*sStringInfo.Buffer)
  1905. X  {
  1906. X    strcpy(qstate.File, sStringInfo.Buffer);
  1907. X    history = hindices = (short *)NULL;
  1908. X    CleanUp(FREEALL_MSG);
  1909. X    if (readfile(qstate.File, &buf)) {
  1910. X      qstate.Asking = 1;
  1911. X      return 1;
  1912. X      } /* if */
  1913. X  } /* if */
  1914. X  return 0;
  1915. X} /* load */
  1916. X
  1917. Xvoid abort() {
  1918. X } /* abort */
  1919. Xint handlemenu(code)
  1920. X  ULONG code;
  1921. X{
  1922. X  ULONG MenuNumber = MENUNUM(code), ItemNumber = ITEMNUM(code);
  1923. X  if ((code != MENUNULL) && (ItemNumber != NOITEM)) {
  1924. X   if (MenuNumber == PROJMENU) {
  1925. X     switch (ItemNumber)
  1926. X       {
  1927. X         case QUITNUM:
  1928. X            return(QUITNOW);
  1929. X            break;
  1930. X         case ABOUTNUM:
  1931. X            about();
  1932. X            break;
  1933. X         case LOADNUM:
  1934. X            if (load()) return(OPENNEWFILE); else return(IGNORE);
  1935. X            break;
  1936. X         case BEGINNUM:
  1937. X            return(STARTASKING);
  1938. X            break;
  1939. X         default:
  1940. X            NonFatalError("Unknown Project Menu selection!\n");
  1941. X            break;
  1942. X         } /* switch */
  1943. X    } /* if project menu */
  1944. X  else if (MenuNumber==OPTMENU) {
  1945. X   switch (ItemNumber)
  1946. X     {
  1947. X       case SWITCHNUM:
  1948. X         return(SWITCHEM);
  1949. X         break;
  1950. X       case IGNORENUM:
  1951. X         qstate.CaseSensitive = !qstate.CaseSensitive;
  1952. X         break;
  1953. X       case ABORTNUM:
  1954. X         abort();
  1955. X         return(ABORTNOW);
  1956. X         break;
  1957. X       case MENUBYTRIAL:
  1958. X         if (qstate.GraphType != BYTRIAL && qstate.GraphType) {
  1959. X            qstate.GraphType = BYTRIAL;
  1960. X            OffMenu(backwindow, TRIALMENUNUM);
  1961. X            OnMenu(backwindow, QUESTMENUNUM);
  1962. X            cleargraph();
  1963. X            drawgraph();
  1964. X            stractivate();
  1965. X            }
  1966. X         return IGNORE;
  1967. X         break;
  1968. X       case MENUBYQUESTION:
  1969. X         if (qstate.GraphType != BYQUESTION && qstate.GraphType) {
  1970. X            qstate.GraphType = BYQUESTION;
  1971. X            OffMenu(backwindow, QUESTMENUNUM);
  1972. X            OnMenu(backwindow, TRIALMENUNUM);
  1973. X            cleargraph();
  1974. X            drawgraph();
  1975. X            stractivate();
  1976. X            }
  1977. X         return IGNORE;
  1978. X         break;
  1979. X       default:
  1980. X         NonFatalError("Unknown Option Menu selection!\n");
  1981. X         break;
  1982. X     } /* switch itemnumber */
  1983. X    } /* if option menu */
  1984. X  } /* if non-null menu selection */
  1985. X return(IGNORE);
  1986. X} /* handlemenu */
  1987. X
  1988. X/* handle button presses */
  1989. Xint handlebuttons(code, mousex, mousey)
  1990. X  ULONG code;
  1991. X  SHORT mousex, mousey;
  1992. X{
  1993. X  if (code == SELECTDOWN) {
  1994. X    int q;
  1995. X#ifdef DEBUG
  1996. X    printf("mouse at %d, %d\n", mousex, mousey);
  1997. X#endif
  1998. X    if ((qstate.GraphType == BYQUESTION) &&
  1999. X        ((q=whichquestion(mousex, mousey))!=-1))
  2000. X       { /* in graph.c */
  2001. X         newquestion = q; /* global, yucky */
  2002. X         return DISPLAYQ;
  2003. X       } /* if q != -1 */
  2004. X    } /* if code */
  2005. X  return IGNORE;
  2006. X} /* handlebuttons */
  2007. X
  2008. X
  2009. X
  2010. Xint bhandlemsg(message)
  2011. X   struct IntuiMessage *message;
  2012. X{
  2013. X  struct IntuiMessage localms;
  2014. X  int i;
  2015. X  UBYTE *s, *d;
  2016. X  ULONG class,code;
  2017. X
  2018. X  s = (UBYTE *)message;
  2019. X  bloop:
  2020. X  d = (UBYTE *)&localms;
  2021. X
  2022. X  /* copy message */
  2023. X  for (i=0;i<sizeof(struct IntuiMessage);i++) *d++=*s++;
  2024. X  ReplyMsg(message);
  2025. X  
  2026. X  class = localms.Class;
  2027. X  code = localms.Code;
  2028. X  switch (class)
  2029. X   {
  2030. X     case REFRESHWINDOW: /* ugh.  this hurts */
  2031. X        /* any more REFRESHWINDOW msgs waiting? */
  2032. X        if (mes = GetMsg(backwindow->UserPort))
  2033. X        {  /* don't redraw if more than one REFRESHWINDOW in a row */
  2034. X/*          printf("waiting: %d ",mes->Class);
  2035. X            if (mes->Class==REFRESHWINDOW) printf("(refresh)\n");
  2036. X            else printf("(not refresh)\n");*/
  2037. X            s = (UBYTE *)mes; message = mes; /* legal? */
  2038. X            if (mes->Class==REFRESHWINDOW) goto bloop;
  2039. X            else { /* some other message.  Redraw and process it */
  2040. X                   redraw();
  2041. X                   goto bloop;
  2042. X                 } /* else */
  2043. X        } /* if */
  2044. X        else redraw();
  2045. X        break;
  2046. X     case GADGETUP:
  2047. X        return(handlegadget((struct Gadget *)localms.IAddress));
  2048. X        break;
  2049. X     case MENUPICK:
  2050. X        return(handlemenu(code));
  2051. X        break;
  2052. X     case MOUSEBUTTONS:
  2053. X        return(handlebuttons(code, localms.MouseX, localms.MouseY));
  2054. X    break;
  2055. X     default:
  2056. X        break;
  2057. X   } /* switch */
  2058. X   return(IGNORE);
  2059. X} /* bhandlemsg */
  2060. X
  2061. X#if 0
  2062. Xvoid main(argc, argv) 
  2063. X   int argc;
  2064. X   union {
  2065. X           char **args;
  2066. X           struct WBStartup *msg; 
  2067. X         } argv;
  2068. X{
  2069. X  ULONG val=0;
  2070. X  if (argc>2) {
  2071. X/*    errnw.DetailPen = atoi(argv.args[1]);
  2072. X    errnw.BlockPen = atoi(argv.args[2]);*/
  2073. X  }
  2074. X  if (argc>4) {
  2075. X    ns.DetailPen = atoi(argv.args[3]);
  2076. X    ns.BlockPen = atoi(argv.args[4]);
  2077. X  }
  2078. X
  2079. X  InitGraphics();
  2080. X
  2081. X  redraw();
  2082. X   /* WaitPort(ewindow->UserPort);*/
  2083. X  while(1) {
  2084. X   while (mes = GetMsg(backwindow->UserPort)) val=bhandlemsg(mes);
  2085. X   if (val == QUITNUM) break;
  2086. X/*   while (mes = GetMsg(ewindow->UserPort)) val=ehandlemsg(mes);*/
  2087. X   if (val == CLOSEWINDOW) break;
  2088. X   }
  2089. X  CloseGraphics();
  2090. X} /* main */
  2091. X#endif
  2092. X#define BaseX 30
  2093. X#define BaseY 40
  2094. X#define Bsize 12
  2095. X
  2096. Xvoid redraw() {
  2097. X   colorwindow(backwindow, GREY7);
  2098. X   SetDrMd(rp, JAM1);
  2099. X
  2100. X   /* draw gadget's border */
  2101. X   DrawBorder(rp,&ibt,0,0); 
  2102. X   if (qtext) DrawQText();
  2103. X   if (qstate.ShowingAns) DrawCText();
  2104. X   if (qstate.GraphType) drawgraph();
  2105. X   RefreshGadgets(&sgadget, backwindow, NULL);
  2106. X } /* redraw */
  2107. END_OF_FILE
  2108. if test 17829 -ne `wc -c <'screen.c'`; then
  2109.     echo shar: \"'screen.c'\" unpacked with wrong size!
  2110. fi
  2111. # end of 'screen.c'
  2112. fi
  2113. echo shar: End of archive 2 \(of 2\).
  2114. cp /dev/null ark2isdone
  2115. MISSING=""
  2116. for I in 1 2 ; do
  2117.     if test ! -f ark${I}isdone ; then
  2118.     MISSING="${MISSING} ${I}"
  2119.     fi
  2120. done
  2121. if test "${MISSING}" = "" ; then
  2122.     echo You have unpacked both archives.
  2123.     rm -f ark[1-9]isdone
  2124. else
  2125.     echo You still need to unpack the following archives:
  2126.     echo "        " ${MISSING}
  2127. fi
  2128. ##  End of shell archive.
  2129. exit 0
  2130. -- 
  2131. Mail submissions (sources or binaries) to <amiga@uunet.uu.net>.
  2132. Mail comments to the moderator at <amiga-request@uunet.uu.net>.
  2133. Post requests for sources, and general discussion to comp.sys.amiga.misc.
  2134.